﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Xml;

namespace WinFormAutoUpdateDemo
{
    public class HttpHelper
    {
        private string _serverUrl = "";
        private string _localPath = "";
        private string _aboutUrl = "";
        private string _startUp = "";

        public string ServerUrl { get => _serverUrl; set => _serverUrl = value; }
        public string LocalPath { get => _localPath; set => _localPath = value; }
        public string AboutUrl { get => _aboutUrl; set => _aboutUrl = value; }
        public string StartUp { get => _startUp; set => _startUp = value; }

        public HttpHelper()
        {
            //本地清单
            XmlDocument xmlLocal = new XmlDocument();
            xmlLocal.Load("updatelist.xml");
            XmlElement application = (XmlElement)xmlLocal.SelectSingleNode("application");
            _serverUrl = application.GetAttribute("serverurl");
            _localPath = application.GetAttribute("localpath");
            _aboutUrl= application.GetAttribute("abouturl");
            _startUp= application.GetAttribute("startup");
        }

        /// <summary>
        /// http下载文件
        /// </summary>
        /// <param name="url">下载文件地址</param>
        /// <param name="path">文件存放地址，包含文件名</param>
        /// <returns></returns>
        public bool HttpDownload(string url, string path)
        {
            string tempPath = System.IO.Path.GetDirectoryName(path) + @"\temp";
            System.IO.Directory.CreateDirectory(tempPath);  //创建临时文件目录
            string tempFile = tempPath + @"\" + System.IO.Path.GetFileName(path); //临时文件
            if (System.IO.File.Exists(tempFile))
            {
                System.IO.File.Delete(tempFile);    //存在则删除
            }
            try
            {
                FileStream fs = new FileStream(tempFile, FileMode.Append, FileAccess.Write, FileShare.ReadWrite);
                // 设置参数
                HttpWebRequest request = WebRequest.Create(url) as HttpWebRequest;
                //发送请求并获取相应回应数据
                HttpWebResponse response = request.GetResponse() as HttpWebResponse;
                //直到request.GetResponse()程序才开始向目标网页发送Post请求
                Stream responseStream = response.GetResponseStream();
                //创建本地文件写入流
                //Stream stream = new FileStream(tempFile, FileMode.Create);
                byte[] bArr = new byte[1024];
                int size = responseStream.Read(bArr, 0, (int)bArr.Length);
                while (size > 0)
                {
                    //stream.Write(bArr, 0, size);
                    fs.Write(bArr, 0, size);
                    size = responseStream.Read(bArr, 0, (int)bArr.Length);
                }
                //stream.Close();
                fs.Close();
                responseStream.Close();
                //System.IO.File.Move(tempFile, path);
                return true;
            }
            catch (Exception ex)
            {
                return false;
            }
        }

        /// <summary>
        /// 获取需要更新的清单
        /// </summary>
        public Dictionary<string, string> CompareLocalAndRemoteFiles()
        {
            Dictionary<string, string> updateList = new Dictionary<string, string>();
            try
            {
                //本地清单
                XmlDocument xmlLocal = new XmlDocument();
                xmlLocal.Load("updatelist.xml");
                XmlElement application = (XmlElement)xmlLocal.SelectSingleNode("application");
                string serverUrl = application.GetAttribute("serverurl");
                string localPath = application.GetAttribute("localpath");
                XmlNodeList localItems = application.SelectSingleNode("items").SelectNodes("item");

                //服务器清单
                XmlDocument xmlRemote = new XmlDocument();
                xmlRemote.Load(serverUrl + "updatelist.xml");
                XmlElement applicationRemote = (XmlElement)xmlRemote.SelectSingleNode("application");
                XmlNodeList remoteItems = applicationRemote.SelectSingleNode("items").SelectNodes("item");

                //比对
                foreach (XmlNode remoteNode in remoteItems)
                {
                    XmlElement remoteEle = (XmlElement)remoteNode;
                    string version = remoteEle.GetAttribute("lastver");
                    string filename = remoteEle.GetAttribute("filename");
                    bool needUpdate = true;
                    foreach (XmlNode localNode in localItems)
                    {
                        XmlElement localEle = (XmlElement)localNode;
                        string localVersion = localEle.GetAttribute("lastver");
                        string localFilename = localEle.GetAttribute("filename");
                        if (filename == localFilename && version.CompareTo(localVersion) < 1)
                        {
                            needUpdate = false;
                        }
                    }

                    if (needUpdate)
                    {
                        updateList.Add(serverUrl + filename, localPath + filename);
                    }
                }
            }
            catch (Exception ex)
            {
                var str = ex.Message;
            }
            return updateList;
        }

        /// <summary>
        /// 更新
        /// </summary>
        public bool Update()
        {
            bool result = false;
            try
            {
                Dictionary<string, string> updateDic = CompareLocalAndRemoteFiles();
                bool success = true;
                foreach (var item in updateDic)
                {
                    bool ret = HttpDownload(item.Key, item.Value);
                    if (!ret)
                    {
                        success = false;
                        break;
                    }
                }

                if (success)
                {
                    result = MoveToTarget();
                }
            }
            catch(Exception ex)
            {
                string str = ex.Message;
                result = false;
            }

            return result;
        }

        /// <summary>
        /// 将临时文件移动到目标位置并删除临时文件
        /// </summary>
        public bool MoveToTarget()
        {
            bool result = false;
            try
            {
                XmlDocument xmlLocal = new XmlDocument();
                xmlLocal.Load("updatelist.xml");
                XmlElement application = (XmlElement)xmlLocal.SelectSingleNode("application");
                string localPath = application.GetAttribute("localpath");

                string tempPath = localPath + @"\temp";
                if (Directory.Exists(tempPath))
                {
                    result = CopyOldLabFilesToNewLab(tempPath, localPath);
                    if (result)
                    {
                        DelectDir(tempPath);
                    }
                }
            }
            catch (Exception ex)
            {
                string str = ex.Message;
                result = false;
            }
            return result;
        }

        /// <summary>
        /// 拷贝oldlab的文件到newlab下面
        /// </summary>
        /// <param name="sourcePath">lab文件所在目录(@"~\labs\oldlab")</param>
        /// <param name="savePath">保存的目标目录(@"~\labs\newlab")</param>
        /// <returns>返回:true-拷贝成功;false:拷贝失败</returns>
        public bool CopyOldLabFilesToNewLab(string sourcePath, string savePath)
        {
            if (!Directory.Exists(savePath))
            {
                Directory.CreateDirectory(savePath);
            }

            #region //拷贝labs文件夹到savePath下
            try
            {
                string[] labDirs = Directory.GetDirectories(sourcePath);//目录
                string[] labFiles = Directory.GetFiles(sourcePath);//文件
                if (labFiles.Length > 0)
                {
                    for (int i = 0; i < labFiles.Length; i++)
                    {
                        if (Path.GetFileName(labFiles[i]) != ".lab")//排除.lab文件
                        {
                            File.Copy(sourcePath + "\\" + Path.GetFileName(labFiles[i]), savePath + "\\" + Path.GetFileName(labFiles[i]), true);
                        }
                    }
                }
                if (labDirs.Length > 0)
                {
                    for (int j = 0; j < labDirs.Length; j++)
                    {
                        Directory.GetDirectories(sourcePath + "\\" + Path.GetFileName(labDirs[j]));

                        //递归调用
                        CopyOldLabFilesToNewLab(sourcePath + "\\" + Path.GetFileName(labDirs[j]), savePath + "\\" + Path.GetFileName(labDirs[j]));
                    }
                }
            }
            catch (Exception ex)
            {
                return false;
            }
            #endregion
            return true;
        }

        /// <summary>
        /// 删除临时文件
        /// </summary>
        /// <param name="srcPath"></param>
        public void DelectDir(string srcPath)
        {
            try
            {
                DirectoryInfo dir = new DirectoryInfo(srcPath);
                FileSystemInfo[] fileinfo = dir.GetFileSystemInfos();  //返回目录中所有文件和子目录
                foreach (FileSystemInfo i in fileinfo)
                {
                    if (i is DirectoryInfo)            //判断是否文件夹
                    {
                        DirectoryInfo subdir = new DirectoryInfo(i.FullName);
                        subdir.Delete(true);          //删除子目录和文件
                    }
                    else
                    {
                        File.Delete(i.FullName);      //删除指定文件
                    }
                }
                dir.Delete(true);
            }
            catch (Exception e)
            {
                throw;
            }
        }

        /// <summary>
        /// 修改本地更新路径
        /// </summary>
        /// <param name="localPath"></param>
        public void UpdateLocalPath(string localPath)
        {
            XmlDocument xmlLocal = new XmlDocument();
            xmlLocal.Load("updatelist.xml");
            XmlElement application = (XmlElement)xmlLocal.SelectSingleNode("application");
            application.SetAttribute("localpath", localPath);
            xmlLocal.Save("updatelist.xml");
        }
    }
}
